class Recoder {
    constructor(sampleRate) {
        this.leftDataList=[]
        this.rightDataList=[]
        this.mediaPlayer=null
        this.audioContext=null
        this.source=null
        this.sampleRate=sampleRate||44100
    }
    start () {
        return new Promise((resolve, reject) => {
            window.navigator.mediaDevices.getUserMedia({
                audio: {
                    sampleRate: 8000, // 采样率
                    channelCount: 1, // 声道
                    audioBitsPerSecond: 64,
                    volume: 1.0, // 音量
                    autoGainControl: true
                }
            }).then(mediaStream => {
                console.log(mediaStream, 'mediaStream')
                this.mediaPlayer=mediaStream
                this.beginRecord(mediaStream)
                resolve()
            }).catch(err => {
                // 如果用户电脑没有麦克风设备或者用户拒绝了，或者连接出问题了等
                // 这里都会抛异常，并且通过err.name可以知道是哪种类型的错误
                console.error(err)
                reject(err)
            })
        })
    }

    beginRecord (mediaStream) {
        let audioContext=new (window.AudioContext||window.webkitAudioContext)()
        // mediaNode包含 mediaStream，audioContext
        let mediaNode=audioContext.createMediaStreamSource(mediaStream)
        console.log(mediaNode, 'mediaNode')
        // 创建一个jsNode
        // audioContext.sampleRate = 8000
        console.log(audioContext, 'audioContext')
        let jsNode=this.createJSNode(audioContext)
        console.log(jsNode, 'jsnode')
        // 需要连到扬声器消费掉outputBuffer，process回调才能触发
        // 并且由于不给outputBuffer设置内容，所以扬声器不会播放出声音
        jsNode.connect(audioContext.destination)
        jsNode.onaudioprocess=this.onAudioProcess.bind(this)
        // 把mediaNode连接到jsNode
        mediaNode.connect(jsNode)
        this.audioContext=audioContext
    }

    onAudioProcess (event) {
        console.log('is recording')
        // 拿到输入buffer Float32Array 
        let audioBuffer=event.inputBuffer
        let leftChannelData=audioBuffer.getChannelData(0)
        // let rightChannelData = audioBuffer.getChannelData(1)

        // 需要克隆一下
        this.leftDataList.push(leftChannelData.slice(0))
        //this.rightDataList.push(rightChannelData.slice(0))
    }

    createJSNode (audioContext) {
        const BUFFER_SIZE=4096
        const INPUT_CHANNEL_COUNT=1
        const OUTPUT_CHANNEL_COUNT=1
        // createJavaScriptNode已被废弃
        let creator=audioContext.createScriptProcessor||audioContext.createJavaScriptNode
        creator=creator.bind(audioContext)
        return creator(BUFFER_SIZE, INPUT_CHANNEL_COUNT, OUTPUT_CHANNEL_COUNT)
    }

    playRecord (arrayBuffer) {
        let blob=new Blob([new Int8Array(arrayBuffer)], {
            type: 'audio/mp3' // files[0].type
        })
        let blobUrl=URL.createObjectURL(blob)
        this.source=blob
        this.blobUrl=blobUrl
        // document.querySelector(‘.audio-node‘).src = blobUrl
        return blobUrl
    }

    stop () {
        // 停止录音
        let leftData=this.mergeArray(this.leftDataList)
        //let rightData = this.mergeArray(this.rightDataList)
        let allData=this.interSingleData(leftData)
        let wavBuffer=this.createWavFile(allData)

        //  转到播放
        let source=this.playRecord(wavBuffer)
        if(source) {
            source=source.slice(5)
        }
        console.log("我最后转换完播放的---------------------", source);
        this.resetRecord()
        return source
    }

    transformArrayBufferToBase64 (buffer) {
        var binary=''
        var bytes=new Uint8Array(buffer)
        for(var len=bytes.byteLength, i=0; i<len; i++) {
            binary+=String.fromCharCode(bytes[i])
        }
        return window.btoa(binary)
    }

    // 停止控件录音
    resetRecord () {
        this.leftDataList=[]
        this.rightDataList=[]
        this.audioContext.close()
        this.mediaPlayer.getAudioTracks().forEach(track => {
            track.stop()
            this.mediaPlayer.removeTrack(track)
        })
    }

    createWavFile (audioData) {
        let channelCount=1
        const WAV_HEAD_SIZE=44
        const sampleBits=16
        let sampleRate=this.sampleRate

        let buffer=new ArrayBuffer(audioData.length*2+WAV_HEAD_SIZE)
        // 需要用一个view来操控buffer
        let view=new DataView(buffer)
        // 写入wav头部信息
        // RIFF chunk descriptor/identifier
        this.writeUTFBytes(view, 0, 'RIFF')
        // RIFF chunk length
        view.setUint32(4, 44+audioData.length*channelCount, true)
        // RIFF type
        this.writeUTFBytes(view, 8, 'WAVE')
        // format chunk identifier
        // FMT sub-chunk
        this.writeUTFBytes(view, 12, 'fmt ')
        // format chunk length
        view.setUint32(16, 16, true)
        // sample format (raw)
        view.setUint16(20, 1, true)
        // stereo (2 channels)
        view.setUint16(22, channelCount, true)
        // sample rate
        view.setUint32(24, sampleRate, true)
        // byte rate (sample rate * block align)
        view.setUint32(28, sampleRate*2, true)
        // block align (channel count * bytes per sample)
        view.setUint16(32, 2*2, true)
        // bits per sample
        view.setUint16(34, 16, true)
        // data sub-chunk
        // data chunk identifier
        this.writeUTFBytes(view, 36, 'data')
        // data chunk length
        view.setUint32(40, audioData.length*2, true)

        console.log(view, 'view')
        let length=audioData.length
        let index=44
        let volume=1
        for(let i=0; i<length; i++) {
            view.setInt16(index, audioData[i]*(0x7FFF*volume), true)
            index+=2
        }
        return buffer
    }

    writeUTFBytes (view, offset, string) {
        var lng=string.length
        for(var i=0; i<lng; i++) {
            view.setUint8(offset+i, string.charCodeAt(i))
        }
    }

    interSingleData (left) {
        var t=left.length;
        let sampleRate=this.audioContext.sampleRate,
            outputSampleRate=this.sampleRate
        sampleRate+=0.0;
        outputSampleRate+=0.0;
        var s=0,
            o=sampleRate/outputSampleRate,
            u=Math.ceil(t*outputSampleRate/sampleRate),
            a=new Float32Array(u);
        for(let i=0; i<u; i++) {
            a[i]=left[Math.floor(s)];
            s+=o;
        }
        return a;
    }

    // 交叉合并左右声道的数据
    interleaveLeftAndRight (left, right) {
        let totalLength=left.length+right.length
        let data=new Float32Array(totalLength)
        for(let i=0; i<left.length; i++) {
            let k=i*2
            data[k]=left[i]
            data[k+1]=right[i]
        }
        return data
    }

    mergeArray (list) {
        let length=list.length*list[0].length
        let data=new Float32Array(length)
        let offset=0
        for(let i=0; i<list.length; i++) {
            data.set(list[i], offset)
            offset+=list[i].length
        }
        return data
    }




}


export default Recoder